package com.example.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;


import com.example.bean.PointBean;
import com.example.studyapplication.R;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description:贝塞尔曲线表格
 * @Author: 葛浩杰
 * @Version: 1.0 2021/2/23
 */
public class CubicBezierChart extends View {
    private String[] y_title = new String[]{"10", "8", "6", "4", "2", "0"};
    private List<String> x_title;
    private List<PointBean> points;
    private Paint mPaint;//X、Y轴文字
    private Paint mLinePaint;//网格横线
    private Paint mBezierPaint;//贝塞尔曲线
    private Paint mOutCircle;//外圆
    private Paint mInsideCircle;//内圆
    private float height;
    private int width;
    private float mScale; //像素密度
    private Path cubicPath;

    private int yTitleLeftMargin = 20;//y轴数据左侧间距
    private int yTitleTextSize = 10;//y轴文字大小
    private int chartRightMargin = 2;//表格最右侧间距
    private int lineRightMargin = 20;//线段最右侧间距
    private int lineLeftMargin = 10;//线段跟Y轴文字左侧间距
    private int xTitleTopMargin = 10;//X轴文字跟最底部线段上间距
    private float intensity = 0.2f;
    private int pointCircle = 5;//原点的半径
    private int bezierWidth = 3;//贝塞尔曲线宽度
    private float xIntensity;
    private int titleW;
    private float yIntensity;
    private float bottomZero;
    private float min_width;
    private float maxValue = 6;

    public CubicBezierChart(Context context) {
        super(context);
    }

    public CubicBezierChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setARGB(255, 214, 214,221);

        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setARGB(255, 50, 51,65);

        mBezierPaint = new Paint();
        mBezierPaint.setAntiAlias(true);
        mBezierPaint.setColor(getResources().getColor(R.color.purple_200));
        mBezierPaint.setStyle(Paint.Style.STROKE);
        mBezierPaint.setStrokeWidth(bezierWidth);

        mOutCircle = new Paint();
        mOutCircle.setAntiAlias(true);
        mOutCircle.setStyle(Paint.Style.STROKE);
        mOutCircle.setARGB(255, 214,214,221);
        mOutCircle.setStrokeWidth(pointCircle-1);

        mInsideCircle = new Paint();
        mInsideCircle.setAntiAlias(true);
        mInsideCircle.setStyle(Paint.Style.FILL);
        mInsideCircle.setARGB(255, 20,195,169);

        mScale = context.getResources().getDisplayMetrics().density;
        points = new ArrayList<>();
        x_title = new ArrayList<>();
        x_title.add("周一");
        x_title.add("周一");
        x_title.add("周一");
        x_title.add("周一");
        x_title.add("周一");
        x_title.add("周一");
        x_title.add("周一");
        cubicPath = new Path();

        points.add(new PointBean(0,0f));
        points.add(new PointBean(1,1f));
        points.add(new PointBean(2,4f));
        points.add(new PointBean(3,6f));
        points.add(new PointBean(4,4f));
        points.add(new PointBean(5,2f));
        points.add(new PointBean(6,5f));
    }

    public CubicBezierChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //尺寸发生改变的时候调用
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
//        weight = 0.7F * w;
        height = 0.7F * h;
        width = w;
//        height = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        cubicPath.reset();
        //如果没有Y轴数据，则直接返回
        if(y_title.length == 0 || x_title.size() == 0){
            return;
        }
        mPaint.setTextSize(yTitleTextSize * mScale);

        //获取y轴数据最上面的文字的宽高
        Rect rect1 = new Rect();
        mPaint.getTextBounds(y_title[1], 0, y_title[1].length(), rect1);
        int titleH = rect1.height();
        titleW = rect1.width();
        //获取X轴数据文字的宽高
        Rect rect2 = new Rect();
        mPaint.getTextBounds(x_title.get(0), 0, 2, rect2);
        int xTitleH = rect2.height();

        //从200dp里面的0.65除以6，因为7个数据，分为6段，
        float min_height = height / (y_title.length-1);
        //用来计算X轴每个点的宽度,去掉一些边距后，有几个就分成几份
        //           总宽       y轴左间距         表格右侧间距         密度      y轴字宽
        min_width = (width - (yTitleLeftMargin  + chartRightMargin) * mScale - titleW) / x_title.size();
        //绘制Y轴数据
        for (int i = y_title.length-1; i >= 0; i--) {
            //绘制0的时候，X是最左侧，y是第一个数字距离上边距的距离+每一块的距离，此处是32
            canvas.drawText(y_title[i], yTitleLeftMargin * mScale,  32 * mScale + min_height * i, mPaint);
        }
        //绘制X轴数据
        for (int i = x_title.size()-1; i >= 0; i--) {
            //                              y轴文字左间距              文字宽度    每段中心点     从0开始，第几个     第一个文字     均分高度乘以个数                    x轴为高度    x轴文字上间距
            canvas.drawText(x_title.get(i), (yTitleLeftMargin ) * mScale + titleW + min_width / 2 + min_width * i, 32 * mScale + min_height * (y_title.length -1) + xTitleH + xTitleTopMargin * mScale, mPaint);
        }

        //绘制Y轴横线
        for (int i = y_title.length-1; i >= 0; i--) {
            //                       y轴文字左间距       线段距离文字左间距          文字宽度         上间距        文字高度一半 //均分高度乘以第几个    宽度          右间距                       //              跟开始y一样              //
            canvas.drawLine((yTitleLeftMargin + lineLeftMargin) * mScale + titleW , 32 * mScale - titleH/2 + min_height * i, width - lineRightMargin * mScale ,(32) * mScale - titleH/2 + min_height * i, mLinePaint);
        }

        // 图标最底部横线的y坐标，去掉了文字的一半
        bottomZero = 32 * mScale + height - titleH/2;

        //绘制曲线
        float prevDx = 0f;
        float prevDy = 0f;
        float curDx = 0f;
        float curDy = 0f;

        // Take an extra point from the left, and an extra from the right.
        // That's because we need 4 points for a cubic bezier (cubic=4), otherwise we get lines moving and doing weird stuff on the edges of the chart.
        // So in the starting `prev` and `cur`, go -2, -1
        // And in the `lastIndex`, add +1

        PointBean prevPrev;
        PointBean prev = points.get(0);
        PointBean cur = points.get(0);
        PointBean next = cur;
        int nextIndex = -1;


        // let the spline start
        //移动到第一个点的位置，开始绘制贝塞尔曲线
        cubicPath.moveTo((yTitleLeftMargin ) * mScale + titleW + min_width / 2, bottomZero - (points.get(0).getY() * min_height));
        //获取x轴的密度
        //            宽度  - （文字左间距           + 图表右间距               ） - 文字宽度-（因为点是中间位置，所以第一个点的左间距和最后一个点的右间距，正好为一个均分宽度）
        xIntensity = (width - ((yTitleLeftMargin + chartRightMargin) * mScale) - titleW - min_width) / (x_title.size()-1);
        //获取Y轴的密度
        yIntensity = height/maxValue;
        for (int j = 1; j < points.size(); j++) {

            prevPrev = prev;
            prev = cur;
            cur = nextIndex == j ? next : points.get(j);

            nextIndex = j + 1 < points.size() ? j + 1 : j;
            next = points.get(nextIndex);

            prevDx = (cur.getX() - prevPrev.getX()) * intensity;
            prevDy = (cur.getY() - prevPrev.getY()) * intensity;
            curDx = (next.getX() - prev.getX()) * intensity;
            curDy = (next.getY() - prev.getY()) * intensity;


            cubicPath.cubicTo(
                    calXControl(prev.getX() + prevDx) , calYControl(prev.getY() + prevDy),
                    calXControl(cur.getX() - curDx), calYControl(cur.getY() - curDy),
                    calXControl(cur.getX()), calYControl(cur.getY()));
        }

        canvas.drawPath(cubicPath, mBezierPaint);

        canvas.save();

        Drawable drawable = getResources().getDrawable(R.drawable.shape_chart_fill);
        cubicPath.lineTo((yTitleLeftMargin) * mScale + titleW + min_width / 2 + (min_width * (x_title.size()-1)), 32 * mScale - titleH/2 + min_height * (y_title.length-1));
        cubicPath.lineTo((yTitleLeftMargin) * mScale + titleW + min_width / 2 , 32 * mScale - titleH/2 + min_height * (y_title.length-1));
        cubicPath.close();

        canvas.clipPath(cubicPath);

        Paint mFillDrawable = new Paint();
        mFillDrawable.setAntiAlias(true);
        mFillDrawable.setStyle(Paint.Style.FILL);
        mFillDrawable.setARGB(0, 90,90,90);
        drawable.setBounds(0,0,width, (int) (32 * mScale - titleH/2 + min_height * (y_title.length-1)));
        drawable.draw(canvas);
        canvas.drawPath(cubicPath,mFillDrawable);

        canvas.restore();
        //绘制数据点
        for (int i = 0; i <= x_title.size()-1; i++) {
            //点的Y坐标
            float topPoint = bottomZero - (points.get(i).getY() * yIntensity);
            //                   y轴文字左间距       线段距离文字左间距          文字宽度   除以2保证中间
            canvas.drawCircle((yTitleLeftMargin) * mScale + titleW + min_width / 2 + min_width * i, topPoint ,pointCircle,mOutCircle);
            canvas.drawCircle((yTitleLeftMargin ) * mScale + titleW + min_width / 2 + min_width * i, topPoint ,pointCircle-1,mInsideCircle);
        }

    }

    /**
     * 根据点计算实际像素位置
     * @param value
     * @return
     */
    private float calXControl(float value){
        return (yTitleLeftMargin) * mScale + titleW + (min_width/2) + value * xIntensity;
    }

    /**
     * 根据点计算实际像素位置
     * @param value
     * @return
     */
    private float calYControl(float value){
        return bottomZero -  value * yIntensity;
    }

    //传入数据并进行绘制
    public void updateThisData(List<Float> data, List<String> name, float maxValue) {
        if(data.size() == 0 || name.size() == 0){
            return;
        }
        for(int i=0; i<= data.size()-1;i++){
            points.add(new PointBean(i,data.get(i)));
        }
        x_title = name;

        if(maxValue <= 6){
            this.maxValue = 6;
            y_title = new String[]{"6", "5", "4", "3", "2", "1", "0"};
        } else if(maxValue <= 10){
            this.maxValue = 10;
            y_title = new String[]{"10", "8", "6", "4", "2", "0"};
        } else if(maxValue <= 18){
            this.maxValue = 18;
            y_title = new String[]{"18", "15", "12", "9", "6", "3", "0"};
        } else {
            this.maxValue = 24;
            y_title = new String[]{"24", "20", "16", "12", "8", "4", "0"};
        }

        invalidate();
    }

}
